﻿using System;
using System.Windows.Forms;
using System.Configuration.Install;
using System.Reflection;
using System.IO;
using System.ServiceProcess;
using Runner.ExchangeFiles;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Configuration;

namespace Runner
{
    public partial class ServiceManager : Form
    {
        public ServiceManager()
        {
            InitializeComponent();
            winServiceName = "ExchangeFilesService";
            winServiceFileName = "ExchangeFilesPharmWinService";
            curDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            exeFileName = curDir + @"\" + winServiceFileName + ".exe";
            try
            {
                sc = new ServiceController(winServiceName);
                if (sc.Status == ServiceControllerStatus.Running)
                {
                    richTextBox1_AddText("Служба запущена");
                }
                if (sc.Status == ServiceControllerStatus.Stopped)
                {
                    richTextBox1_AddText("Служба остановлена");
                }
                if (sc.Status == ServiceControllerStatus.Paused)
                {
                    richTextBox1_AddText("Служба приостановлена");
                }
            }
            catch (Exception ex)
            {
                richTextBox1_AddText("Не удалось определить состояние службы:\n" + ex.Message);
            }
            finally
            {
                sc.Close();
            }
        }

        private string winServiceName;
        private string winServiceFileName;
        private string curDir;
        private string exeFileName;
        private ServiceController sc;

        private void ServiceManager_Load(object sender, EventArgs e)
        {
            GetServiceSettings();
        }

        public void buttonIns_Click(object sender, EventArgs e)
        {
            try
            {
                richTextBox1_AddText("Начало установки службы...");
                InstallServ();
                richTextBox1_AddText("Служба установлена");
            }
            catch (Exception ex)
            {
                richTextBox1_AddText("Возникли ошибки:\n" + ex.Message);
            }
        }

        public void InstallServ()
        {
            try
            {
                ManagedInstallerClass.InstallHelper(new[] { exeFileName });
            }
            catch (Exception ex)
            {
                throw new Exception("Install()\n" + ex.Message);
            }
        }

        private void richTextBox1_AddText(string message)
        {
            richTextBox1.Text = DateTime.Now.ToString("HH:mm:ss") + " " + message + "\n" + richTextBox1.Text;
            richTextBox1.Refresh();
        }

        public void buttonRun_Click(object sender, EventArgs e)
        {
            try
            {
                richTextBox1_AddText("Запуск службы...");
                sc = new ServiceController(winServiceName);
                StartServ();
                richTextBox1_AddText("Служба запущена");
            }
            catch (Exception ex)
            {
                richTextBox1_AddText("Возникли ошибки:\n" + ex.Message);
            }
            finally
            {
                sc.Close();
            }
        }

        public void StartServ()
        {
            try
            {
                sc.Start();
                sc.WaitForStatus(ServiceControllerStatus.Running);
            }
            catch (Exception ex)
            {
                throw new Exception("StartServ(ServiceController servContr)\n" + ex.Message);
            }
        }

        public void buttonStop_Click(object sender, EventArgs e)
        {
            try
            {
                richTextBox1_AddText("Остановка службы...");
                sc = new ServiceController(winServiceName);
                StopServ();
                richTextBox1_AddText("Служба остановлена");
            }
            catch (Exception ex)
            {
                richTextBox1_AddText("Возникли ошибки:\n" + ex.Message);
            }
            finally
            {
                sc.Close();
            }
        }

        public void StopServ()
        {
            try
            {
                sc.Stop();
                sc.WaitForStatus(ServiceControllerStatus.Stopped);
            }
            catch (Exception ex)
            {
                throw new Exception("StopServ(ServiceController servContr)\n" + ex.Message);
            }
        }

        public void buttonDel_Click(object sender, EventArgs e)
        {
            try
            {
                richTextBox1_AddText("Остановка службы...");
                sc = new ServiceController(winServiceName);
                StopServ();
                richTextBox1_AddText("Служба остановлена");
            }
            catch (Exception ex)
            {
                richTextBox1_AddText("Возникли ошибки:\n" + ex.Message);
            }
            finally
            {
                sc.Close();
                try
                {
                    richTextBox1_AddText("Удаление службы...");
                    UninstallServ();
                    richTextBox1_AddText("Служба удалена");
                }
                catch (Exception ex)
                {
                    richTextBox1_AddText("Возникли ошибки:\n" + ex.Message);
                }
            }
        }

        public void UninstallServ()
        {
            try
            {
                ManagedInstallerClass.InstallHelper(new[] { "/u", exeFileName });
            }
            catch (Exception ex)
            {
                throw new Exception("Install()\n" + ex.Message);
            }
        }

        public void buttonUpd_Click(object sender, EventArgs e)
        {
            try
            {

                richTextBox1_AddText("Обновление службы");
                ExchangeFilesClient client = new ExchangeFilesClient();
                richTextBox1_AddText("Определение версий службы");
                FileNameVersion fnv = client.GetWinServiceInfo();
                string currvers = FileVersionInfo.GetVersionInfo(exeFileName).FileVersion;
                richTextBox1_AddText("Текущая версия на клиенте: " + currvers + "\nАктуальная версия на сервере: " + fnv.FileVersion);


                if (fnv.FileVersion != currvers)
                {
                    sc = new ServiceController(winServiceName);
                    if (sc.Status != ServiceControllerStatus.Stopped)
                    {
                        richTextBox1_AddText("Остановка службы...");
                        StopServ();
                        richTextBox1_AddText("Служба остановлена");
                    }
                    bool upd = false;
                    var files = client.GetUpdFiles();
                    foreach (FileInfoDC file in files)
                        if (Path.GetFileName(file.Path) == Path.GetFileName(fnv.FileName))
                        {
                            richTextBox1_AddText("Загрузка новой версии файла...");
                            upd = DownloadFile(file);
                            if(upd) richTextBox1_AddText("Файл загружен");
                            else richTextBox1_AddText("Файл не загружен");
                            break;
                        }
                    if (upd)
                    {
                        Configuration config = ConfigurationManager.OpenExeConfiguration(exeFileName);
                        client.ClientFileVersionUpd(Convert.ToInt32(config.AppSettings.Settings["clientid"].Value), Path.GetFileName(fnv.FileName), FileVersionInfo.GetVersionInfo(exeFileName).FileVersion);
                    }
                }
                else richTextBox1_AddText("Обновление не нужно");
            }
            catch (Exception ex)
            {
                richTextBox1_AddText("Возникли ошибки:\n" + ex.Message);
            }
            finally
            {
                if (sc.Status == ServiceControllerStatus.Stopped)
                {
                    richTextBox1_AddText("Запуск службы...");
                    sc = new ServiceController(winServiceName);
                    StartServ();
                    richTextBox1_AddText("Служба запущена");
                }
            }
        }

        private bool DownloadFile(FileInfoDC file)
        {
            var log = new LogClass();
            log.LogIns(8, file.Path, file.Size, file.MD5Checksum);
            ExchangeFilesClient client = new ExchangeFilesClient();
            var ret = false;
            var fileName = Path.GetFileName(file.Path);
            var currFile = exeFileName + "$";
            var chunkLeight = client.GetChunkLeight();
            var countChunk = (int)Math.Ceiling(file.Size / (double)chunkLeight);
            if (File.Exists(currFile)) File.Delete(currFile);
            var stream = File.Create(currFile);
            try
            {
                for (var i = 0; i < countChunk; i++)
                {
                    var chunk = client.GetChunk(file.Path, i);
                    var chunkBytes = Convert.FromBase64String(chunk.Chunk);
                    var curFileLengthNew = new FileInfo(currFile).Length + chunkBytes.Length;
                    if (chunkBytes.Length == (int)chunkLeight ||
                        ((long)chunkBytes.Length < chunkLeight && i == file.CountChunk - 1 && curFileLengthNew == file.Size))
                        if (ComputeMD5Checksum(chunkBytes) == chunk.MD5Checksum)
                        {
                            stream.Write(chunkBytes, 0, chunkBytes.Length);
                            stream.Flush();
                            if (new FileInfo(currFile).Length == file.Size)
                            {
                                stream.Close();
                                if (ComputeMD5Checksum(currFile) == file.MD5Checksum)
                                    ret = true;
                            }
                        }
                        else
                        {
                            i--;
                            log.LogIns(10, file.Path, file.Size, file.MD5Checksum);
                        }
                    else
                    {
                        i--;
                        log.LogIns(10, file.Path, file.Size, file.MD5Checksum);
                    }
                }
                if (ret)
                {
                    if (File.Exists(currFile.TrimEnd('$'))) File.Delete(currFile.TrimEnd('$'));
                    File.Move(currFile, currFile.TrimEnd('$'));
                    log.LogIns(9, file.Path, file.Size, file.MD5Checksum);
                }
                else log.LogIns(10, file.Path, file.Size, file.MD5Checksum);
            }
            catch (Exception ex)
            {
                log.LogIns(10, file.Path, file.Size, file.MD5Checksum, ex.Message);
                throw new Exception("DownloadFile(FileInfoDC file)\n" + ex.Message);
            }
            finally
            {
                stream.Close();
                client.Close();
            }
            return ret;
        }

        static string ComputeMD5Checksum(string path)
        {
            using (FileStream fs = System.IO.File.OpenRead(path))
            {
                byte[] fileData = new byte[fs.Length];
                fs.Read(fileData, 0, (int)fs.Length);
                byte[] checkSum = new MD5CryptoServiceProvider().ComputeHash(fileData);
                return BitConverter.ToString(checkSum).Replace("-", String.Empty);
            }
        }

        static string ComputeMD5Checksum(byte[] bytes)
        {
            var checkSum = new MD5CryptoServiceProvider().ComputeHash(bytes);
            return BitConverter.ToString(checkSum).Replace("-", String.Empty);
        }

        public void UpdServ()
        {
            LogClass log = new LogClass();
            try
            {
                log.LogIns(35);
                ExchangeFilesClient client = new ExchangeFilesClient();
                FileNameVersion fnv = client.GetWinServiceInfo();
                string currvers = FileVersionInfo.GetVersionInfo(exeFileName).FileVersion;

                if (fnv.FileVersion != currvers)
                {
                    log.LogIns(37);
                    sc = new ServiceController(winServiceName);
                    if (sc.Status != ServiceControllerStatus.Stopped)
                    {
                        StopServ();
                    }
                    bool upd = false;
                    var files = client.GetUpdFiles();
                    foreach (FileInfoDC file in files)
                        if (Path.GetFileName(file.Path) == Path.GetFileName(fnv.FileName))
                        {
                            log.LogIns(39);
                            upd = DownloadFile(file);
                            break;
                        }

                    if (upd)
                    {
                        log.LogIns(40);
                        Configuration config = ConfigurationManager.OpenExeConfiguration(exeFileName);
                        client.ClientFileVersionUpd(Convert.ToInt32(config.AppSettings.Settings["clientid"].Value), Path.GetFileName(fnv.FileName), FileVersionInfo.GetVersionInfo(exeFileName).FileVersion);
                    }
                }
            }
            catch (Exception)
            {
                log.LogIns(44);
            }
            finally
            {
                if (sc.Status != ServiceControllerStatus.Running)
                {
                    sc = new ServiceController(winServiceName);
                    StartServ();
                }
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                Configuration config = ConfigurationManager.OpenExeConfiguration(exeFileName);
                config.AppSettings.Settings["clientid"].Value = clientId.Text;
                config.AppSettings.Settings["pharmcode"].Value = pharmCode.Text;
                config.AppSettings.Settings["path_in"].Value = pathIn.Text;
                config.AppSettings.Settings["path_out"].Value = pathOut.Text;
                config.AppSettings.Settings["path_map_in"].Value = pathIn_map.Text;
                config.AppSettings.Settings["path_map_out"].Value = pathOut_map.Text;
                config.AppSettings.Settings["periodMinute"].Value = periodMinute.Text;
                config.Save(ConfigurationSaveMode.Modified);
                MessageBox.Show("Настройки измененены.\nОни вступят в силу после перезапуска клиента");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void GetServiceSettings()
        {
            try
            {
                Configuration config = ConfigurationManager.OpenExeConfiguration(exeFileName);
                clientId.Text = config.AppSettings.Settings["clientid"].Value;
                if (clientId.Text != "" && clientId.Text != "0") clientId.Enabled = false;
                pharmCode.Text = config.AppSettings.Settings["pharmcode"].Value;
                if (pharmCode.Text != "" && pharmCode.Text != "0") pharmCode.Enabled = false;
                pathIn.Text = config.AppSettings.Settings["path_in"].Value;
                pathOut.Text = config.AppSettings.Settings["path_out"].Value;
                pathIn_map.Text = config.AppSettings.Settings["path_map_in"].Value;
                pathOut_map.Text = config.AppSettings.Settings["path_map_out"].Value;
                periodMinute.Text = config.AppSettings.Settings["periodMinute"].Value;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void buttonStopAndRun_Click(object sender, EventArgs e)
        {
            try
            {
                richTextBox1_AddText("Остановка службы...");
                sc = new ServiceController(winServiceName);
                StopServ();
                richTextBox1_AddText("Служба остановлена");
                richTextBox1_AddText("Запуск службы...");
                StartServ();
                richTextBox1_AddText("Служба запущена");
            }
            catch (Exception ex)
            {
                richTextBox1_AddText("Возникли ошибки:\n" + ex.Message);
            }
            finally
            {
                sc.Close();
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            pathIn_map.Text = GetPath(pathIn_map.Text);
        }

        private string GetPath(string path)
        {
            string dir = path;
            FolderBrowserDialog dial = new FolderBrowserDialog();
            dial.RootFolder = Environment.SpecialFolder.Desktop;
            if (Directory.Exists(path)) dial.SelectedPath = path;
            dial.ShowNewFolderButton = true;
            if (dial.ShowDialog() == DialogResult.OK) dir = dial.SelectedPath;
            return dir;
        }

        private void button3_Click(object sender, EventArgs e)
        {
            pathOut_map.Text = GetPath(pathOut_map.Text);
        }

        private void button5_Click(object sender, EventArgs e)
        {
            pathIn.Text = GetPath(pathIn.Text);
        }

        private void button4_Click(object sender, EventArgs e)
        {
            pathOut.Text = GetPath(pathOut.Text);
        }

        private void button6_Click(object sender, EventArgs e)
        {
            //- Запуск обмена вручную
            richTextBox1_AddText("Запуск сеанса связи вручную");
            sc = new ServiceController(winServiceName);
            sc.ExecuteCommand(255);
        }
    }
}
